/**
 * 							PHYSICAL MEMORY MANAGEMENT
 * @brief	physical memory management
 * @author	chy.
 * @note	this file only management the physical memory page!
 * @comment	ARM MMU support many modes.But we use 4KB per page.
 */

#ifndef	_K_MEM_PHYSICAL_H_
#define	_K_MEM_PHYSICAL_H_

#include "mem_basedefine.h"

/********************************************************************
 * 						comments and defines						*
 ********************************************************************/
/*
	comments:
	 Every memory page(4KB size) is managed by one byte(1B)!
	 figure:
	 --------------------------
	 |7				2 |	1 |	0 |
	 |    reserved    | M | U |
	 --------------------------
	 0 bit U:	indicate whether this physical page being used.0 unused;1 using!
	 1 bit M:	indicate the page using mode if page is been using!0 system mode,1 user mode
	 2~7 bit:	reserved for extending.
*/

/** @brief	physical memory manage macros */
#define	K_MEM_PHY_USERMOD	0x02
#define	K_MEM_PHY_SYSMOD	0x00

// page manager table index to physical memory address
#define	K_MEM_PHY_PMTIDX2PHYMMADDR(__idx__)			((__idx__) << 12)			// 4KB per page.

// physical memory address to page manager table
#define	K_MEM_PHY_PHYMMADDR2PMTIDX(__phy_addr__)	((__phy_addr__)>> 12)		// ...

// check whether using
#define	K_MEM_PHY_PAGEUSING(__idx__)				(g_s_k_mem_phy_pagemgrtable[(__idx__)] & 0x01)
#define	K_MEM_PHY_SETUSING(__idx__)					(g_s_k_mem_phy_pagemgrtable[(__idx__)] = g_s_k_mem_phy_pagemgrtable[(__idx__)] | 0x01)
#define	K_MEM_PHY_SETFREE(__idx__)					(g_s_k_mem_phy_pagemgrtable[(__idx__)] = g_s_k_mem_phy_pagemgrtable[(__idx__)] & 0x00)

// check using mode
#define	K_MEM_PHY_PAGEMODE(__idx__)					((g_s_k_mem_phy_pagemgrtable[(__idx__)] & 0x02 )>> 1)

// set page used by user mode
#define	K_MEM_PHY_SETUSERMODE(__idx__)				\
{	\
	K_MEM_PHY_SETUSING(__idx__);	\
	(g_s_k_mem_phy_pagemgrtable[(__idx__)] = g_s_k_mem_phy_pagemgrtable[(__idx__)] | 0x02);	\
}

// set page used by system mode
#define	K_MEM_PHY_SETSYSMODE(__idx__)				\
{ 	\
	K_MEM_PHY_SETUSING(__idx__);	\
	(g_s_k_mem_phy_pagemgrtable[(__idx__)] = g_s_k_mem_phy_pagemgrtable[(__idx__)] & 0xfd);	\
}


// page type
typedef enum {
	K_MEM_PHY_SYSTEM = 0,	//

	K_MEM_PHY_NORMAL		//
}EN_K_MEM_PHY_USE_MODE;

/**
 * @BRIEF	:	Initialize Physical Memory
 * @PARAM	:	ram_phy_startaddr	physical starting address of RAM in system
 * @PARAM	:	ram_phy_endaddr		physical end address of RAM in system
 * @RETURN	:	void
 */
void k_mem_phy_init(unsigned int ram_phy_startaddr, unsigned int ram_phy_endaddr);

/**
 * @BRIEF	:	Allocate a Physical Memory Page
 * @PARAM	:	mem_mode			indicate whether need to allocate in OS space
 * @PARAM	:	page_count			count of physical pages need to allocate in continuous
 * @RETURN	:	the physical address of page start
 * @NOTE	:	this can allocate continuous physical pages
 * 			:	this function thinks interrupt is disabled!
 * 			: =>So,need to control interrupt when using this.
 * 			:	$$ In fact, we don't need to allocate continuous physical pages usually
 */
void* k_mem_phy_allocate(EN_K_MEM_PHY_USE_MODE mem_mode, unsigned page_count);

/**
 * @BRIEF	:	Free a Physical Memory Page
 * @PARAM	:	phy_addr			physical address of page to free
 * @RETURN	:	void
 * @NOTE	: =>this will free just one physical page!
 */
void k_mem_phy_free(unsigned int phy_addr);


/**
 * @BRIEF	:	Allocate First Level Page Table
 * @PARAM	:	void
 * @RETURN	:	physical address of First Level Page Table
 * @NOTE	:	this function will allocate 4 continuous physical pages
 * 			:	also, it' started at 16KB bound, as system needed.
 * @WARNNING: =>This function thinks that interrupt has been disabled
 * 			:	So, make sure interrupt has been disabled when calling this!
 */
void* k_mem_phy_allocate_flpt(void);

#endif	//_K_MEM_PHYSICAL_H_
